package com.coszero.utils.file

import android.util.Log
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.UnsupportedEncodingException
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.RejectedExecutionException

/**
 *
 *
 * 使用方法如下：
 *
 *
 * new DownloadSaveImgs( "/mnt/sdcard/test", listUrl, new DownloadStateListener() {
 * public void onFinish() {
 * //图片下载成功后，实现您的代码
 * }
 * public void onFailed() {
 * //图片下载失败后，实现您的代码
 * }
 * }).startDownload();
 *
 *
 * Desc： 多图下载
 *
 * @author xmqian
 * Email:xmqian93@163.com
 * Date: 2020/8/13 0013 14:57
 * @version 1
 */
class DownloadSaveImgs(// 下载目录
    private val downloadPath: String, // 下载链接集合
    private val listURL: List<String>,
    // 下载状态监听，提供回调
    var listener: DownloadStateListener
) {
    // 下载个数
    private var size = 0

    // 下载完成回调接口
    interface DownloadStateListener {
        fun onFinish()

        fun onFailed()
    }

    /**
     * 暂未提供设置
     */
    fun setDefaultExecutor() {
    }

    /**
     * 开始下载
     */
    fun startDownload() {
        // 首先检测path是否存在
        val downloadDirectory = File(downloadPath)
        if (!downloadDirectory.exists()) {
            downloadDirectory.mkdirs()
        }

        for (url in listURL) {
            //捕获线程池拒绝执行异常
            try {
                // 线程放入线程池
                DEFAULT_TASK_EXECUTOR!!.execute {
                    downloadBitmap(
                        url
                    )
                }
            } catch (e: RejectedExecutionException) {
                e.printStackTrace()
                Log.e(TAG, "thread pool rejected error")
                listener.onFailed()
            } catch (e: Exception) {
                e.printStackTrace()
                listener.onFailed()
            }
        }
    }

    /**
     * 下载图片
     *
     * @param urlString
     * @return
     */
    private fun downloadBitmap(urlString: String): File? {
        val fileName = urlString
        // 图片命名方式
        val cacheFile = File(
            createFilePath(
                File(
                    downloadPath
                ), fileName
            )
        )

        var urlConnection: HttpURLConnection? = null
        var out: BufferedOutputStream? = null

        try {
            val url = URL(urlString)
            urlConnection = url.openConnection() as HttpURLConnection
            val `in`: InputStream = BufferedInputStream(
                urlConnection!!.inputStream, IO_BUFFER_SIZE
            )
            out = BufferedOutputStream(
                FileOutputStream(cacheFile),
                IO_BUFFER_SIZE
            )

            var b: Int
            while ((`in`.read().also { b = it }) != -1) {
                out.write(b)
            }
            // 每下载成功一个，统计一下图片个数
            statDownloadNum()
            return cacheFile
        } catch (e: IOException) {
            // 有一个下载失败，则表示批量下载没有成功
            Log.e(TAG, "download $urlString error")
            listener.onFailed()
        } finally {
            urlConnection?.disconnect()
            if (out != null) {
                try {
                    out.close()
                } catch (e: IOException) {
                    Log.e(
                        TAG,
                        "Error in downloadBitmap - $e"
                    )
                }
            }
        }

        return null
    }

    /**
     * 统计下载个数
     */
    private fun statDownloadNum() {
        synchronized(lock) {
            size++
            if (size == listURL.size) {
                Log.d(TAG, "download finished total $size")
                // 释放资源
                DEFAULT_TASK_EXECUTOR!!.shutdownNow()
                // 如果下载成功的个数与列表中 url个数一致，说明下载成功
                listener.onFinish() // 下载成功回调
            }
        }
    }

    companion object {
        private const val TAG = "DownloadSaveImgs"
        const val IO_BUFFER_SIZE: Int = 8 * 1024
        private const val CACHE_FILENAME_PREFIX = "cache_"
        private val SINGLE_TASK_EXECUTOR: ExecutorService? = null
        private var LIMITED_TASK_EXECUTOR: ExecutorService? = null
        private val FULL_TASK_EXECUTOR: ExecutorService? = null
        private val DEFAULT_TASK_EXECUTOR: ExecutorService?
        private val lock = Any()

        init {
            // SINGLE_TASK_EXECUTOR = (ExecutorService)
            // Executors.newSingleThreadExecutor();
            LIMITED_TASK_EXECUTOR = Executors
                .newFixedThreadPool(1) as ExecutorService
            // FULL_TASK_EXECUTOR = (ExecutorService)
            // Executors.newCachedThreadPool();
            DEFAULT_TASK_EXECUTOR = LIMITED_TASK_EXECUTOR
        }

        /**
         * Creates a constant cache file path given a target cache directory and an
         * image key.
         *
         * @param cacheDir
         * @param key
         * @return
         */
        fun createFilePath(cacheDir: File, key: String): String? {
            try {
                // Use URLEncoder to ensure we have a valid filename, a tad hacky
                // but it will do for
                // this example
                return (cacheDir.absolutePath + File.separator + CACHE_FILENAME_PREFIX
                        + URLEncoder.encode(key.replace("*", ""), "UTF-8"))
            } catch (e: UnsupportedEncodingException) {
                Log.e(TAG, "createFilePath - $e")
            }

            return null
        }
    }
}


